package cate.game.play.skill.effect;


import cate.common.table.d.GDAttr;
import cate.common.table.d.GDBuff;
import cate.common.table.d.GDSkill;
import cate.common.util.XT;
import cate.game.attr.FightAttr;
import cate.game.play.base.HpCfg;
import cate.game.play.fighter.Fighter;
import cate.game.play.proce.action.ctx.SkillActionCtx;
import cate.game.play.skill.Skill;
import cate.game.play.skill.SkillParam;
import cate.game.play.skill.effect.base.SE;
import easy.java.dev.note.NoteClass;
import easy.java.dev.note.NoteField;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@NoteClass("一个技能的总体效果")
public class SkillEffect {

    @NoteField("技能")
    public Skill skr;

    @NoteField(value = "技能核心效果",detail = "由效果类型和效果配置决定")
    public SE core;

    @NoteField("buff添加SE列表")
    public List<BuffAddSE> buffAddList;

    @NoteField("技能释放者临时属性")
    private FightAttr actorAttr;

    @NoteField("技能释放者附加伤害")
    private double exDamage;

    @NoteField("附加的buff驱散数量限制")
    private int dispelLimit;

    @NoteField("无视护盾比例")
    private double ignShieldRate;

    @NoteField("无视禁活")
    private boolean ignNoRebirth;

    @NoteField("血量调整比例")
    private double hpChangeRate;

    @NoteField("血量结算配置")
    private List<HpCfg> hpCfgs;

    @NoteField("重写伤害性质")
    private Byte nature;

    @NoteField("buff添加概率调整")
    private int exBuffChance;

    public void addActorAttr(FightAttr attr) {
        if (actorAttr == null) {
            actorAttr = new FightAttr();
        }
        actorAttr.add(attr);
    }

    public void addExDamage(double damage) {
        this.exDamage += damage;
    }

    public void addDispelLimit(int limit) {
        if (dispelLimit < 0) {
            return;
        }
        if (limit < 0) {
            dispelLimit = -1;
            return;
        }
        dispelLimit += limit;
    }

    public void addIgnShieldRate(double ignShieldRate) {this.ignShieldRate+= ignShieldRate;}

    public void setIgnNoRebirth(boolean ignNoRebirth) {this.ignNoRebirth = ignNoRebirth;}

    public void addHpChangeRate(double rate){this.hpChangeRate+=rate;}

    @NoteField("针对每个目标的效果ctx")
    private Map<Integer,SkillEffectTargetCtx> targetCtxMap = new HashMap<>();

    public SkillEffectTargetCtx getTargetCtx(Fighter target) {
        return getTargetCtx(target.getPid());
    }

    public SkillEffectTargetCtx getTargetCtx(int targetPid) {
        SkillEffectTargetCtx ctx = targetCtxMap.get(targetPid);
        if (ctx == null) {
            ctx = new SkillEffectTargetCtx(targetPid);
            targetCtxMap.put(targetPid, ctx);
        }
        return ctx;
    }

    protected SkillEffect() {}

    public SkillEffect(Skill skr) {
        this.skr = skr;
        this.core = SEFactory.build(this.skr.cfg.row.effectType, this.skr.cfg);
        this.core.setup(this);
        buildBuffAddSe();
        handleParam(skr.param);
    }

    private void handleParam(SkillParam param) {
        addActorAttr(param.getCastAttr());
        setIgnNoRebirth(param.isIgnNoBirth());
    }

    private void buildBuffAddSe() {
        for (String buffAddCfg : this.skr.cfg.getBuffAddRules()) {
            if (buffAddList == null) {
                buffAddList = new ArrayList<>();
            }
            BuffAddSE buffAddSe = new BuffAddSE();
            buffAddSe.parse(buffAddCfg);
            buffAddSe.setup(this);
            buffAddList.add(buffAddSe);
        }
    }


    /**
     * 获取施法者针对特定目标的属性提升
     * @param targetPid
     * @return
     */
    public FightAttr getActorAttr(int targetPid) {
        FightAttr attr = new FightAttr();
        attr.add(this.actorAttr);
        attr.add(getTargetCtx(targetPid).getActorAttr());
        return attr;
    }

    /**
     * 获取目标的临时属性提升
     * @param targetPid
     * @return
     */
    public FightAttr getTargetAttr(int targetPid){
        return getTargetCtx(targetPid).getTargetAttr();
    }

    /**
     * 获取附加伤害
     * @return
     */
    public double getExDamage() {
        return this.exDamage;
    }

    /**
     * 是否无视护盾
     * @param targetPid
     * @return
     */
    public double ignShieldRate(int targetPid) {
        return ignShieldRate + getTargetCtx(targetPid).ignShieldRate();
    }

    /**
     * 是否无视禁活
     * @return
     */
    public boolean isIgnNoRebirth(){
        return this.ignNoRebirth;
    }

    /**
     * 获取血量调整比例
     * @return
     */
    public double getHpChangeRate(int targetPid) {
        return hpChangeRate + getTargetCtx(targetPid).getHpChangeRate();
    }


    public void addHpCfgByCoeff(double coeff) {
        if (hpCfgs == null) {
            hpCfgs = new ArrayList<>();
        }
        hpCfgs.add(new HpCfg(GDSkill.Base.CASTER, GDAttr.ATT, coeff));
    }

    public List<HpCfg> getHpCfgs(int targetPid) {
        return XT.mergeNew(hpCfgs, getTargetCtx(targetPid).getHpCfgs());
    }

    /**
     * 获取额外的驱散数量
     * @return
     */
    public int getDispelLimit(){return dispelLimit;}

    public void addExBuffChance(int chance){
        this.exBuffChance +=chance;
    }

    public int getExBuffChance(int targetPid) {
        return exBuffChance + getTargetCtx(targetPid).getExBuffChance();
    }

    public void setNature(byte nature){
        this.nature = nature;
    }

    public Byte getNature() {
        return nature;
    }



    /** 结算 */
    public void settle(SkillActionCtx action, Fighter target) {
        //技能结算前脚本处理
        if (skr.active != null) {
            skr.active.beforeSingleEffect(action, this, target);
        }
        //技能结算前的buff添加和移除
        this.settleBuff(action, target, GDBuff.SettleOrder.BEFORE);
        //施法者临时属性
        handleCasterTempAttr(action.getActor(),target);
        //目标被击临时属性
        handleTargetTempAttr(action.getActor(), target);

        this.core.settle(action, target);

        //技能结算后的buff添加和移除
        this.settleBuff(action, target, GDBuff.SettleOrder.AFTER);
        //技能结算后脚本处理
        if (skr.active != null) {
            skr.active.afterSingleEffect(action, this, target);
        }
    }


    /**
     * 结算buff
     *
     * @param order 处理顺序
     */
    private void settleBuff(SkillActionCtx action, Fighter target, byte order) {
        if (buffAddList != null) {
            buffAddList.forEach(
                    se -> {
                        if (se.order == order) {
                            se.settle(action, target);
                        }
                    });
        }
    }


    /**
     * 施法者临时属性
     * @param actor
     * @param target
     */
    private void handleCasterTempAttr(Fighter actor, Fighter target) {
        for (String code : skr.cfg.getCasterAttrs()) {
            SkillTempAttrHandler.settle(code, this, actor, target, true);
        }
    }

    /**
     * 目标被击临时属性
     * @param actor
     * @param target
     */
    private void handleTargetTempAttr(Fighter actor, Fighter target) {
        for (Skill skill : target.skill.getAllSkill()) {
            if (XT.isNotBlank(skill.cfg.row.targetTempAttrs)) {
                for (String code : skill.cfg.row.targetTempAttrs) {
                    SkillTempAttrHandler.settle(code, this, actor, target, false);
                }
            }
        }
    }
}
